﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Taste.Internal
{
    internal class TriggerEffect
    {
        private Delegate _effect;
        private Delegate _condition;
        private Type _paramType;

        public bool CanFire(object parameter)
        {
            try
            {
                parameter = ConvertParameter(parameter, _paramType);
                if(_effect != null)
                    return (_condition == null || (bool)_condition.DynamicInvoke(parameter));
                else
                    return false;
            }
            catch(Exception)
            {
                return false;
            }
        }

        public void Fire(object parameter)
        {
            if(this.CanFire(parameter))
            {
                try
                {
                    if(_effect != null)
                        _effect.DynamicInvoke(ConvertParameter(parameter, _paramType));
                }
                catch(TargetInvocationException ex)
                {
                    throw ex.InnerException;
                }
            }
        }

        private static object ConvertParameter(object parameter, Type targetType)
        {
            string str = parameter as string;
            if(str != null && targetType != null && targetType.IsEnum)
                return Enum.Parse(targetType, str, true);

            return parameter;
        }

        public void SetEffect(Action effect, Func<bool> condition)
        {
            Action<object> parameterizedEffect = null;
            if(effect != null)
                parameterizedEffect = o => effect();

            Func<object, bool> parameterizedCondition = null;
            if(condition != null)
                parameterizedCondition = o => condition();

            this.SetEffect<object>(parameterizedEffect, parameterizedCondition);
        }

        public void SetEffect<TParam>(Action<TParam> effect, Func<TParam, bool> condition)
        {
            if(typeof(TParam) != typeof(object))
                _paramType = typeof(TParam);
            _effect = effect;
            _condition = condition;
        }

    }
}
